package cn.iocoder.yudao.module.system.service.examclass;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.module.system.controller.admin.examclass.vo.*;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserSaveReqVO;
import cn.iocoder.yudao.module.system.convert.examclass.ExamClassStudentConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.examclass.ExamClassDO;
import cn.iocoder.yudao.module.system.dal.dataobject.examclass.ExamClassStudentDO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.mysql.examclass.ExamClassStudentMapper;
import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum;
import cn.iocoder.yudao.module.system.service.permission.PermissionService;
import cn.iocoder.yudao.module.system.service.permission.RoleService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import cn.iocoder.yudao.module.system.util.PinyinUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;

/**
 * 班级学生关联 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
@Slf4j
public class ExamClassStudentServiceImpl implements ExamClassStudentService {

    @Resource
    private ExamClassStudentMapper examClassStudentMapper;

    @Resource
    private ExamClassService examClassService;

    @Resource
    private AdminUserService adminUserService;
    
    @Resource
    private PermissionService permissionService;
    
    @Resource
    private RoleService roleService;

    @Override
    public Long createExamClassStudent(ExamClassStudentCreateReqVO createReqVO) {
        // 校验班级存在
        ExamClassDO examClass = examClassService.getExamClass(createReqVO.getClassId());
        
        // 校验学生是否已在班级中
        validateStudentNotInClass(createReqVO.getClassId(), createReqVO.getStudentId());
        
        // 校验学号唯一性
        validateStudentNoUnique(null, createReqVO.getStudentNo());
        
        // 插入
        ExamClassStudentDO examClassStudent = ExamClassStudentConvert.INSTANCE.convert(createReqVO);
        examClassStudent.setClassName(examClass.getClassName()); // 设置班级名称
        examClassStudent.setJoinTime(LocalDateTime.now());
        examClassStudentMapper.insert(examClassStudent);
        
        // 更新班级学生人数
        examClassService.updateStudentCount(createReqVO.getClassId());
        
        // 返回
        return examClassStudent.getId();
    }

    @Override
    public void updateExamClassStudent(ExamClassStudentUpdateReqVO updateReqVO) {
        // 校验存在
        validateExamClassStudentExists(updateReqVO.getId());
        
        // 校验学号唯一性
        validateStudentNoUnique(updateReqVO.getId(), updateReqVO.getStudentNo());
        
        // 更新
        ExamClassStudentDO updateObj = ExamClassStudentConvert.INSTANCE.convert(updateReqVO);
        examClassStudentMapper.updateById(updateObj);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteExamClassStudent(Long id) {
        // 校验存在
        ExamClassStudentDO examClassStudent = validateExamClassStudentExists(id);
        
        // 删除
        examClassStudentMapper.deleteById(id);
        
        // 更新班级学生人数
        examClassService.updateStudentCount(examClassStudent.getClassId());
    }

    private ExamClassStudentDO validateExamClassStudentExists(Long id) {
        ExamClassStudentDO examClassStudent = examClassStudentMapper.selectById(id);
        if (examClassStudent == null) {
            throw exception(EXAM_CLASS_STUDENT_NOT_EXISTS);
        }
        return examClassStudent;
    }

    private void validateStudentNotInClass(Long classId, Long studentId) {
        ExamClassStudentDO examClassStudent = examClassStudentMapper.selectByClassIdAndStudentId(classId, studentId);
        if (examClassStudent != null) {
            throw exception(EXAM_CLASS_STUDENT_EXISTS);
        }
    }

    private void validateStudentNoUnique(Long id, String studentNo) {
        // 【说明】由于考号现在包含部门ID前缀，理论上是全局唯一的
        // 但为了向后兼容旧数据，这里仍然保留全局唯一性检查
        // 如果未来需要改为部门内唯一，可以使用下面注释的代码
        
        ExamClassStudentDO examClassStudent = examClassStudentMapper.selectByStudentNo(studentNo);
        if (examClassStudent == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的学生
        if (id == null) {
            throw exception(EXAM_CLASS_STUDENT_NO_DUPLICATE);
        }
        if (!examClassStudent.getId().equals(id)) {
            throw exception(EXAM_CLASS_STUDENT_NO_DUPLICATE);
        }
        
        /* 部门内唯一性检查的实现（未来可选）：
        Long currentDeptId = SecurityFrameworkUtils.getLoginUserDeptId();
        List<ExamClassStudentDO> students = examClassStudentMapper.selectList(
            new LambdaQueryWrapperX<ExamClassStudentDO>()
                .eq(ExamClassStudentDO::getStudentNo, studentNo)
                .eq(ExamClassStudentDO::getDeptId, currentDeptId));
        // 然后检查是否重复...
        */
    }

    @Override
    public ExamClassStudentDO getExamClassStudent(Long id) {
        return examClassStudentMapper.selectById(id);
    }

    @Override
    public List<ExamClassStudentDO> getExamClassStudentList(Collection<Long> ids) {
        return examClassStudentMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<ExamClassStudentDO> getExamClassStudentPage(ExamClassStudentPageReqVO pageReqVO) {
        return examClassStudentMapper.selectPage(pageReqVO);
    }

    @Override
    public List<ExamClassStudentDO> getExamClassStudentList(ExamClassStudentPageReqVO exportReqVO) {
        return examClassStudentMapper.selectList(exportReqVO);
    }

    @Override
    public List<ExamClassStudentDO> getStudentListByClassId(Long classId) {
        return examClassStudentMapper.selectListByClassId(classId);
    }

    @Override
    public List<ExamClassStudentDO> getClassListByStudentId(Long studentId) {
        return examClassStudentMapper.selectListByStudentId(studentId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchAddStudentsToClass(Long classId, List<Long> studentIds) {
        // 校验班级存在
        ExamClassDO examClass = examClassService.getExamClass(classId);
        
        for (Long studentId : studentIds) {
            // 校验学生是否已在班级中
            ExamClassStudentDO existing = examClassStudentMapper.selectByClassIdAndStudentId(classId, studentId);
            if (existing == null) {
                ExamClassStudentDO examClassStudent = new ExamClassStudentDO();
                examClassStudent.setClassId(classId);
                examClassStudent.setStudentId(studentId);
                examClassStudent.setClassName(examClass.getClassName()); // 设置班级名称
                examClassStudent.setJoinTime(LocalDateTime.now());
                examClassStudent.setStatus(1);
                examClassStudentMapper.insert(examClassStudent);
            }
        }
        
        // 更新班级学生人数
        examClassService.updateStudentCount(classId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeStudentFromClass(Long classId, Long studentId) {
        ExamClassStudentDO examClassStudent = examClassStudentMapper.selectByClassIdAndStudentId(classId, studentId);
        if (examClassStudent != null) {
            examClassStudentMapper.deleteById(examClassStudent.getId());
            // 更新班级学生人数
            examClassService.updateStudentCount(classId);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchRemoveStudentsFromClass(Long classId, List<Long> studentIds) {
        for (Long studentId : studentIds) {
            removeStudentFromClass(classId, studentId);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ExamClassStudentImportRespVO importStudents(Long classId, MultipartFile file) throws IOException {
        List<ExamClassStudentImportExcelVO> importStudents = ExcelUtils.read(file, ExamClassStudentImportExcelVO.class);
        // 如果为空，则不导入
        if (CollUtil.isEmpty(importStudents)) {
            throw exception(USER_IMPORT_LIST_IS_EMPTY);
        }

        // 获取班级信息
        ExamClassDO examClass = examClassService.getExamClass(classId);
        if (examClass == null) {
            throw exception(EXAM_CLASS_NOT_EXISTS);
        }

        ExamClassStudentImportRespVO respVO = ExamClassStudentImportRespVO.builder()
                .createStudentNames(0).updateStudentNames(0).failureStudentNames(0)
                .failureStudentList(new ArrayList<>()).failureReasons(new HashMap<>()).build();

        importStudents.forEach(importStudent -> {
            try {
                // 【修复】校验学号是否存在（同时传入班级名称，避免多部门数据混乱）
                ExamClassStudentDO existingStudent = examClassStudentMapper.selectByStudentNoAndClassName(
                    importStudent.getStudentNo(), examClass.getClassName());
                
                if (existingStudent != null) {
                    // 更新学生信息
                    existingStudent.setStudentName(importStudent.getStudentName());
                    existingStudent.setPhone(importStudent.getPhone());
                    existingStudent.setEmail(importStudent.getEmail());
                    existingStudent.setStatus(importStudent.getStatus());
                    examClassStudentMapper.updateById(existingStudent);
                    respVO.setUpdateStudentNames(respVO.getUpdateStudentNames() + 1);
                } else {
                    // 创建新学生和登录账号
                    Long userId = createStudentUserAccount(importStudent, examClass);

                    // 创建班级学生关联记录
                    ExamClassStudentDO newStudent = ExamClassStudentConvert.INSTANCE.convert(importStudent);
                    newStudent.setClassId(classId);
                    newStudent.setStudentId(userId);
                    newStudent.setClassName(examClass.getClassName()); // 设置班级名称
                    newStudent.setJoinTime(LocalDateTime.now());
                    examClassStudentMapper.insert(newStudent);
                    respVO.setCreateStudentNames(respVO.getCreateStudentNames() + 1);

                    log.info("成功为学生{}创建登录账号，用户ID: {}", importStudent.getStudentName(), userId);
                }
            } catch (Exception ex) {
                log.error("导入学生{}失败: {}", importStudent.getStudentName(), ex.getMessage(), ex);
                respVO.setFailureStudentNames(respVO.getFailureStudentNames() + 1);
                respVO.getFailureStudentList().add(importStudent.getStudentName());
                respVO.getFailureReasons().put(importStudent.getStudentName(), ex.getMessage());
            }
        });

        // 更新班级学生人数
        examClassService.updateStudentCount(classId);

        return respVO;
    }

    @Override
    public List<ExamClassStudentImportExcelVO> getImportTemplate() {
        return Arrays.asList(
                ExamClassStudentImportExcelVO.builder().studentNo("2024001").studentName("张三")
                        .phone("13800138000").email("zhangsan@example.com").status(1).build(),
                ExamClassStudentImportExcelVO.builder().studentNo("2024002").studentName("李四")
                        .phone("13800138001").email("lisi@example.com").status(1).build()
        );
    }

    @Override
    public List<StudentAccountExportExcelVO> getStudentAccountsForExport(Long classId) {
        // 获取班级信息
        ExamClassDO examClass = examClassService.getExamClass(classId);
        if (examClass == null) {
            throw exception(EXAM_CLASS_NOT_EXISTS);
        }
        
        // 获取班级学生列表
        List<ExamClassStudentDO> studentList = examClassStudentMapper.selectListByClassId(classId);
        
        List<StudentAccountExportExcelVO> result = new ArrayList<>();
        for (ExamClassStudentDO student : studentList) {
            // 获取学生用户信息
            AdminUserDO user = adminUserService.getUser(student.getStudentId());
            if (user != null) {
                StudentAccountExportExcelVO exportVO = StudentAccountExportExcelVO.builder()
                    .userId(user.getId())
                    .username(user.getUsername())
                    .studentNo(student.getStudentNo())
                    .studentName(student.getStudentName())
                    .classId(examClass.getId())
                    .className(examClass.getClassName())
                    .classCode(examClass.getClassCode())
                    .grade(examClass.getGrade())
                    .initialPassword("88888888") // 默认初始密码
                    .mobile(user.getMobile())
                    .email(user.getEmail())
                    .status(user.getStatus() == 0 ? "正常" : "停用")
                    .joinTime(student.getJoinTime())
                    .createTime(user.getCreateTime())
                    .build();
                result.add(exportVO);
            }
        }
        
        return result;
    }

    /**
     * 为学生创建登录账号
     *
     * @param importStudent 导入的学生信息
     * @param examClass 班级信息
     * @return 创建的用户ID
     */
    private Long createStudentUserAccount(ExamClassStudentImportExcelVO importStudent, ExamClassDO examClass) {
        // 生成用户名：学生姓名拼音 + 班级编码
        String username = PinyinUtils.generateUsername(importStudent.getStudentName(), examClass.getClassCode());

        // 检查用户名是否已存在，如果存在则添加数字后缀
        String finalUsername = ensureUniqueUsername(username);

        // 创建用户请求对象
        UserSaveReqVO createUserReq = new UserSaveReqVO();
        createUserReq.setUsername(finalUsername);
        createUserReq.setNickname(importStudent.getStudentName());
        createUserReq.setPassword("88888888"); // 统一密码为8个8，会自动加密
        createUserReq.setStatus(1); // 启用状态

        // 设置手机号和邮箱（如果有）
        if (StrUtil.isNotBlank(importStudent.getPhone())) {
            createUserReq.setMobile(importStudent.getPhone());
        }
        if (StrUtil.isNotBlank(importStudent.getEmail())) {
            createUserReq.setEmail(importStudent.getEmail());
        }

        // 创建用户账号
        Long userId = adminUserService.createUser(createUserReq);
        
        // 自动分配学生角色
        assignStudentRole(userId);

        log.info("为学生{}创建登录账号成功，用户名: {}, 密码已加密存储",
                importStudent.getStudentName(), finalUsername);

        return userId;
    }

    /**
     * 确保用户名唯一性
     *
     * @param baseUsername 基础用户名
     * @return 唯一的用户名
     */
    private String ensureUniqueUsername(String baseUsername) {
        String username = baseUsername;
        int suffix = 1;

        // 检查用户名是否已存在
        while (adminUserService.getUserByUsername(username) != null) {
            username = baseUsername + suffix;
            suffix++;
        }

        return username;
    }
    
    /**
     * 为用户分配学生角色
     * 
     * @param userId 用户ID
     */
    private void assignStudentRole(Long userId) {
        try {
            // 查找学生角色
            List<RoleDO> roles = roleService.getRoleList();
            RoleDO studentRole = roles.stream()
                .filter(role -> RoleCodeEnum.STUDENT.getCode().equals(role.getCode()))
                .findFirst()
                .orElse(null);
            
            if (studentRole != null) {
                // 分配学生角色
                permissionService.assignUserRole(userId, Collections.singleton(studentRole.getId()));
                log.info("成功为用户ID={}分配学生角色", userId);
            } else {
                log.warn("未找到学生角色，请先在系统中创建code为'student'的角色");
            }
        } catch (Exception e) {
            log.error("为用户ID={}分配学生角色失败", userId, e);
        }
    }

}